﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;

namespace Dragoon
{
  /// <summary>
  /// Extension methods
  /// </summary>
  static class Extensions
  {
    public static void Normal(this Vector3 p0, ref Vector3 p1, ref Vector3 p2, ref Vector3 result)
    {
      Vector3 o1 = p1 - p0;
      Vector3 o2 = p2 - p0;
      Vector3.Cross(ref o1, ref o2, out result);
      result.Normalize();
    }

    public static int ToIntFloor(this float v)
    {
      return (int)v;
    }

    public static int ToIntCeiling(this float v)
    {
      return (int)v + 1;
    }

    private static IEnumerable<Point> ToPointNeighbours(this Vector2 v)
    {
      float x = v.X;
      float y = v.Y;
      yield return new Point(x.ToIntFloor(), y.ToIntFloor());
      yield return new Point(x.ToIntCeiling(), y.ToIntFloor());
      yield return new Point(x.ToIntCeiling(), y.ToIntCeiling());
      yield return new Point(x.ToIntFloor(), y.ToIntCeiling());
    }

    public static Point[] ToNeighbourArray(this Vector2 v)
    {
      Point[] result = new Point[4];
      int i = 0;
      foreach (var p in v.ToPointNeighbours())
        result[i++] = p;
      return result;
    }

    public static Vector3 ToVector3Height(this Vector2 v, float h)
    {
      return new Vector3(v.X, h, v.Y);
    }

    public static Vector3 ToVector3Height(this Point v, float h)
    {
      return new Vector3(v.X, h, v.Y);
    }

    /// <summary>
    /// Returns the position on the line to target
    /// </summary>
    /// <param name="v"></param>
    /// <param name="target"></param>
    /// <param name="relativeDistance">0 = this 1.0 = target</param>
    /// <returns></returns>
    public static Vector2 PositionOnLineTo(this Vector2 v, Vector2 target, float relativeDistance)
    {
      // y1 = m * x1 + c
      // y2 = m * x2 + c
      // c = y1 - m * x1 
      // y1 - m * x1 = y2 - m * x2
      // y1 - y2 = m (x1 - x2)
      // m = (y1 - y2) / x1 - x2)            
      var m = (v.Y - target.Y) / (v.X - target.X);
      // y3 = m * x3 + c
      // y3 = y1 + (m * d) * (y2 - y1)
      // x3 = x1 + (m * d) * (x2 - x1)
      var md = m * relativeDistance;
      return new Vector2(v.X + md * (target.X - v.X), v.Y + md * (target.Y - v.Y));
    }

    public static float AngleTo(this Vector2 v, Vector2 target)
    {
      var cosTheta = Vector2.Dot(v, target) / (v.Length() * target.Length());
      return (float) Math.Acos(cosTheta);
    }

  }
}
